// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file specifies a recursive data storage class called Value intended for
// storing setting and other persistable data. It includes the ability to 
// specify (recursive) lists and dictionaries, so it's fairly expressive.
// However, the API is optimized for the common case, namely storing a 
// hierarchical tree of simple values. Given a DictionaryValue root, you can
// easily do things like:
//
// root->SetString("global.pages.homepage", "http://goateleporter.com");
// std::string homepage = "http://google.com"; // default/fallback value
// root->GetString("global.pages.homepage", &homepage);
//
// where "global" and "pages" are also DictionaryValues, and "homepage" is a
// string setting. If some elements of the path didn't exist yet, the
// SetString() method would create the missing elements and attach them to root
// before attaching the homepage value.

#ifndef BASE_VALUES_H_
#define BASE_VALUES_H_
#pragma once

#include <iterator>
#include <map>
#include <string>
#include <vector>

// This file declares "using base::Value", etc. at the bottom, so that
// current code can use these classes without the base namespace. In
// new code, please always use base::Value, etc. or add your own
// "using" declaration.
// http://crbug.com/88666
namespace {

class BinaryValue;
class DictionaryValue;
class FundamentalValue;
class ListValue;
class StringValue;
class Value;

typedef std::vector<Value*> ValueVector;
typedef std::map<std::string, Value*> ValueMap;

// The Value class is the base class for Values. A Value can be instantiated
// via the Create*Value() factory methods, or by directly creating instances of
// the subclasses.
class Value {
public:
	enum Type {
		TYPE_NULL = 0;
		TYPE_BOOLEAN, 
		TYPE_INTEGER,
		TYPE_DOUBLE,
		TYPE_STRING,
		TYPE_BINARY,
		TYPE_DICTIONARY,
		TYPE_LIST
	};

	virtual ~Value();

	// Convenience methods for creating Value objects for various
	// kinds of values without thinking about which class implements them.
	// These can always be expected to return a valid Value*.
	static Value* CreateNullValue();
	static FundamentalValue* CreateBooleanValue(bool in_value);
	static FundamentalValue* CreateIntegerValue(int in_value);
	static FundamentalValue* CreateDoubleValue(double in_value);
	static StringValue* CreateStringValue(const std::string& in_value);

	// Returns the type of the value stored by the current Value object.
	// Each type will be implemented by only one subclass of Value, so it's
	// safe to use the Type to determine whether you can cast from 
	// Value* to (Implementing Class)*. Also, a Value object never changes
	// its type after construction.
	Type GetType() const { return type_; }

	// Returns true if the current object represents a given type.
	bool IsType(Type type) const { return type == type_; }

	// These methods allow the convenient retrieval of settings.
	// If the current setting object can be converted into the given type,
	// the value is returned through the |out_value| parameter and true is
	// returned; otherwise, false is returned and |out_value| is unchanged.
	virtual bool GetAsBoolean(bool* out_value) const;
	virtual bool GetAsInteger(int* out_value) const;
	virtual bool GetAsDouble(double* out_value) const;
	virtual bool GetAsString(std::string* out_value) const;
	virtual bool GetAsList(ListValue** out_value);
	virtual bool GetAsList(const ListValue** out_value) const;
	virtual bool GetAsDictionary(DicionaryValue** out_value);
	virtual bool GetAsDictionary(const DictionaryValue** out_value) const;

	// This creates a deep copy of the entire Value tree, and returns a pointer
	// to the copy. The caller gets ownership of the copy, of course.
	//
	// Subclasses return their own type directly in their overrides;
	// this works because C++ supports covariant return types.
	virtual Value* DeepCopy() const;

	// Compares if two Value objects have equal contents.
	virtual bool Equals(const Value* other) const;

	// Compares if two Value objects have equal contents. Can handle NULLs.
	// NULLs are considered equal but different from Value::CreateNullValue().
	static bool Equals(const Value* a, const Value* b);

protected:
	// This isn't safe for end-users (they should use the Create*Value()
	// static methods above), but it's useful for subclasses.
	explicit Value(Type type);

private:
	Value();

	Type type_;

	DISALLOW_COPY_AND_ASSIGN(Value);
};

// FundamentalValue represents the simple fundamental types of values.
class FundamentalValue : public Value {
public:
	explicit FundamentalValue(bool in_value);
	explicit FundamentalValue(int in_value);
	explicit FundamentalValue(double in_value);
	virtual	~FundamentalValue();

	// Overridden from Value:
	virtual bool GetAsBoolean(bool* out_value) const OVERRIDE;
	virtual bool GetAsInteger(int* out_value) const OVERRIDE;
	virtual bool GetAsDouble(double* out_value) const OVERRIDE;
	virtual FundamentalValue* DeepCopy() const OVERRIDE;
	virtual bool Equals(const Value* other) const OVERRIDE;

private:
	union {
		bool boolean_value_;
		int integer_value_;
		double double_value_;
	}

	DISALLOW_COPY_AND_ASSIGN(FundamentalValue);
};


class StringValue : public Value {
public:
	// Initializes a StringValue with a UTF-8 narrow character string.
	explicit StringValue(const std::string& in_value);

	// Initializes a StringValue with a wstring.
	explicit StringValue(const std::wstring& in_value);

	virtual ~StringValue();

	// Overridden from Value:
	virtual bool GetAsString(std::string* out_value) const OVERRIDE;
	virtual bool GetAsString(std::wstring* out_value) const OVERRIDE;
	virtual StringValue* DeepCopy() const OVERRIDE;
	virtual bool Equals(const Value* other) const OVERRIDE;

private:
	std::string value_;

	DISALLOW_COPY_AND_ASSIGN(StringValue);
};

class BinaryValue : public Value {
public:
	virtual ~BinaryValue();

	// Creates a Value to represent a binary buffer. The new object takes
	// ownership of the pointer passed in, if successful.
	// Returns NULL if buffer is NULL.
	static BinaryValue* Create(char* buffer, size_t size);

	// For situations where you want to keep ownership of your buffer, this
	// factory method creates a new BinaryValue by copying the contents of the
	// buffer that's passed in.
	// Returns NULL if buffer is NULL.
	static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size);

	size_t GetSize() const { return size_; }
	char* GetBuffer() { return buffer_; }
	const char* GetBuffer() const { return buffer_; }

	// Overridden from Value:
	virtual BinaryValue* DeepCopy() const OVERRIDE;
	virtual bool Equals(const Value* other) const OVERRIDE;

private:
	// Constructor is private so that only objects with valid buffer pointers
	// and size values can be created.
	BinaryValue(char* buffer, size_t size);

	char* buffer_;
	size_t size_;

	DISALLOW_COPY_AND_ASSIGN(BinaryValue);
};

// DictionaryValue provides a key-value dictionary with (optional) "path"
// parsing for recursive access; seee the comment at the top of the file. Keys
// are |std::string|s and should be UTF-8 encoded.
class DictionaryValue : public Value {
public:
	DictionaryValue();
	virtual ~DictionaryValue();

	// Overridden from Value:
	virtual bool GetAsDictionary(DictionaryValue** out_value) OVERRIDE;
	virtual bool GetAsDictionary(const DictionaryValue** out_value) const OVERRIDE;

	// Returns true if the current dictionary has a value for the given key.
	bool HasKey(const std::string& key) const;

	// Returns the number of Values in this dictionary.
	size_t size() const { return dictionary_.size(); }

	// Returns whether the dictionary is empty.
	bool empty() const { return dictionary_.empty(); }

	// Clears any current contents of this dictionary.
	void Clear();

	// Sets the Value associated with the given path starting from this object.
	// A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
	// into the next DictionaryValue down. Obviously, "." can't be used
	// within a key, but there are no other restrictions on keys.
	// If the key at any step of the way doesn't exist, or exists but isn't
	// a DictionaryValue, a new DictionaryValue will be created and attached
	// to the path in that location.
	// Note that the dictionary takes ownership of the value referenced by 
	// |in_value|, and therefore |in_value| must be non-NULL.
	void Set(const std::string& path, Value* in_value);

	// Convenience forms of Set(). These methods will replace any existing
	// value at that path, even if it has a different type.
	void SetBoolean(const std::string& path, bool in_value);
	void SetInteger(const std::string& path, int in_value);
	void SetDouble(const std::string& path, double in_value);
	void SetString(const std::string& path, const std::string& in_value);

	// Like Set(), but without special treatment of '.', This allows e.g. URLs to
	// be used as paths.
	void SetWithoutPathExpansion(const std::string& key, Value* in_value);

	// Gets the Value associated with the given path starting from this object.
	// A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
	// into the next DictionaryValue down. If the path can be resolved
	// successfully, the value for the last key in the path will be returned
	// through the |out_value| parameter, and the function will return true.
	// Otherwise, it will return false and |out_value| will be untouched.
	// Note that the dictionary always owns the value that's returned.
	bool Get(const std::string& path, Value** out_value) const;

	// These are convenience forms of Get(). The value will be retrieved
	// and the return value will be true if the path is valid and the value at 
	// the end of the path can be returned in the form specified.
	bool GetBoolean(const std::string& path, bool* out_value) const;
	bool GetInteger(const std::string& path, int* out_value) const;
	bool GetDouble(const std::string& path, double* out_value) const;
	bool GetString(const std::string& path, std::string* out_value) const;
	bool GetBinary(const std::string& path, BinaryValue** out_value) const;
	bool GetDictionary(const std::string& path, DictionaryValue** out_value) const;
	bool GetList(const std::string& path, ListValue** out_value) const;

	// Like Get(), but without special treatment of '.'. This allows e.g. URLs to
	// be used as paths.



};


}
